//创建 Kvue构造函数

class Kvue {
    constructor(options){
        //保存选项
        this.$options = options
        this.$data = options.data

        //响应化处理
        observe(this.$data)

        //代理
        proxy(this,'$data')

        // 创建编译器
        new Compiler(options.el, this)
    }
}


// 代理函数，方便用户直接访问$data中的数据
function proxy(vm,sourceKey){
    // vm[sourceKey]就是vm[$data]
    Object.keys(vm[sourceKey]).forEach(key){
        Object.defineProperty(vm,key,{
            get(){
                return vm[sourceKey][key]
            },
            set(newVal){
                vm[sourceKey][key] = newVal
            }
        })
    }
}

//响应化处理
function observe(obj){
    if(typeof obj !== 'object' || obj == null){
        //希望传入的是obj
        return 
    }
    // 创建Observer实例
  new Observer(obj)
}

class Observer {
    constructor(value){
        this.value = value

        //判断其类型
        if(typeof value === 'object'){
            this.walk(value)
        }
    }

    //对象数据响应化
    walk(obj) {
        Object.key(obj).forEach(key =>{
            defineReactive(obj,key,obj[key])
        })
    }
    
}

function defineReactive(obj,key,val){
    //递归
    observe(val)

    //创建一个Dep和当前key 一一对应
    const dep = new Dep;

    //对传人obj进行访问拦截
    Object.defineProperty(obj,key,{
        get(){
            console.log('get'+key);
            // 依赖收集在这里
            Dep.target && dep.addDep(Dep.target)
            return val
        },
        set(newVal){
            if(newVal !== val){
                // 如果传入的newVal依然是obj，需要做响应化处理
                observe(newVal)
                val = newVal
                dep.notify()
            }
        }
    })
}

//Dep: 依赖，管理某个key相关所有Watcher实例
class Dep {
    constructor(){
        this.deps = []
    }
    addDep(dep){
        this.deps.push(dep)
    }

    notify(){
        this.deps.forEach(dep => dep.update())
    }
}

//观察者：保存更新函数，值发生变化调用更新函数
 
class Watcher{
    constructor(vm,key,updateFn){
        this.vm = vm
        this.key = key
        this.updateFn = updateFn

        //Dep.target 静态属性上设置为当前watcher实例
        Dep.target = this
        this.vm[this.key] //读取触发了getter
        Dep.targer = null //收集完就置空
    }
}